import React, {
  useState,
  useEffect,
  useContext,
  useReducer,
  useMemo,
  useCallback,
  useRef,
  useImperativeHandle,
  useLayoutEffect,
  useDebugValue,
  forwardRef,
  createContext,
} from 'react';

// ==================== useState 示例 ====================

/**
 * useState - 状态管理基础
 * 类似于 Vue 3 的 ref() 和 reactive()
 */
const UseStateExample: React.FC = () => {
  const [count, setCount] = useState(0);
  const [name, setName] = useState('');

  return (
    <div style={{ padding: '20px', border: '1px solid #ccc', margin: '10px' }}>
      <h3>useState 示例</h3>
      <p>计数: {count}</p>
      <button onClick={() => setCount(count + 1)}>增加</button>
      <button onClick={() => setCount(count - 1)}>减少</button>

      <div style={{ marginTop: '10px' }}>
        <input
          type="text"
          value={name}
          onChange={e => setName(e.target.value)}
          placeholder="输入姓名"
        />
        <p>你好, {name || '陌生人'}!</p>
      </div>
    </div>
  );
};

// ==================== useEffect 示例 ====================

/**
 * useEffect - 副作用处理
 * 类似于 Vue 3 的 watchEffect() 和 watch()
 */
const UseEffectExample: React.FC = () => {
  const [data, setData] = useState<string | null>(null);
  const [loading, setLoading] = useState(true);

  // 模拟数据获取
  useEffect(() => {
    console.log('useEffect - 组件挂载或依赖项变化');

    const timer = setTimeout(() => {
      setData('这是从服务器获取的数据');
      setLoading(false);
    }, 2000);

    // 清理函数
    return () => {
      console.log('useEffect - 清理函数执行');
      clearTimeout(timer);
    };
  }, []); // 空依赖数组，只在挂载时执行

  // 监听数据变化
  useEffect(() => {
    if (data) {
      console.log('数据已更新:', data);
    }
  }, [data]);

  return (
    <div style={{ padding: '20px', border: '1px solid #ccc', margin: '10px' }}>
      <h3>useEffect 示例</h3>
      {loading ? <p>加载中...</p> : <p>数据: {data}</p>}
    </div>
  );
};

// ==================== useContext 示例 ====================

/**
 * useContext - 跨组件状态共享
 * 类似于 Vue 3 的 provide() 和 inject()
 */
interface ThemeContextType {
  theme: string;
  toggleTheme: () => void;
}

const ThemeContext = createContext<ThemeContextType>({
  theme: 'light',
  toggleTheme: () => {},
});

const ThemeProvider: React.FC<{ children: React.ReactNode }> = ({
  children,
}) => {
  const [theme, setTheme] = useState('light');

  const toggleTheme = () => {
    setTheme(prevTheme => (prevTheme === 'light' ? 'dark' : 'light'));
  };

  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
};

const ThemedButton: React.FC = () => {
  const { theme, toggleTheme } = useContext(ThemeContext);

  return (
    <button
      onClick={toggleTheme}
      style={{
        backgroundColor: theme === 'light' ? '#fff' : '#333',
        color: theme === 'light' ? '#000' : '#fff',
        padding: '10px',
        border: '1px solid #ccc',
      }}
    >
      当前主题: {theme} (点击切换)
    </button>
  );
};

const UseContextExample: React.FC = () => {
  return (
    <ThemeProvider>
      <div
        style={{ padding: '20px', border: '1px solid #ccc', margin: '10px' }}
      >
        <h3>useContext 示例</h3>
        <ThemedButton />
      </div>
    </ThemeProvider>
  );
};

// ==================== useReducer 示例 ====================

/**
 * useReducer - 复杂状态管理
 * 类似于 Vue 3 的 reactive() + 方法
 */
interface Todo {
  id: number;
  text: string;
  completed: boolean;
}

type TodoAction =
  | { type: 'ADD_TODO'; text: string }
  | { type: 'TOGGLE_TODO'; id: number }
  | { type: 'REMOVE_TODO'; id: number };

const todoReducer = (state: Todo[], action: TodoAction): Todo[] => {
  switch (action.type) {
    case 'ADD_TODO':
      return [
        ...state,
        { id: Date.now(), text: action.text, completed: false },
      ];
    case 'TOGGLE_TODO':
      return state.map(todo =>
        todo.id === action.id ? { ...todo, completed: !todo.completed } : todo
      );
    case 'REMOVE_TODO':
      return state.filter(todo => todo.id !== action.id);
    default:
      return state;
  }
};

const UseReducerExample: React.FC = () => {
  const [todos, dispatch] = useReducer(todoReducer, []);
  const [inputText, setInputText] = useState('');

  const addTodo = () => {
    if (inputText.trim()) {
      dispatch({ type: 'ADD_TODO', text: inputText });
      setInputText('');
    }
  };

  return (
    <div style={{ padding: '20px', border: '1px solid #ccc', margin: '10px' }}>
      <h3>useReducer 示例 - Todo List</h3>
      <div>
        <input
          type="text"
          value={inputText}
          onChange={e => setInputText(e.target.value)}
          placeholder="输入待办事项"
          onKeyPress={e => e.key === 'Enter' && addTodo()}
        />
        <button onClick={addTodo}>添加</button>
      </div>
      <ul>
        {todos.map(todo => (
          <li
            key={todo.id}
            style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}
          >
            <span
              onClick={() => dispatch({ type: 'TOGGLE_TODO', id: todo.id })}
            >
              {todo.text}
            </span>
            <button
              onClick={() => dispatch({ type: 'REMOVE_TODO', id: todo.id })}
            >
              删除
            </button>
          </li>
        ))}
      </ul>
    </div>
  );
};

// ==================== useMemo 和 useCallback 示例 ====================

/**
 * useMemo - 计算属性缓存
 * 类似于 Vue 3 的 computed()
 * useCallback - 函数缓存
 * 类似于 Vue 3 的函数式 ref()
 */
const UseMemoCallbackExample: React.FC = () => {
  const [count, setCount] = useState(0);
  const [text, setText] = useState('');

  // 使用 useMemo 缓存计算结果
  const expensiveValue = useMemo(() => {
    console.log('计算 expensiveValue...');
    let result = 0;
    for (let i = 0; i < 1000000; i++) {
      result += i;
    }
    return result + count;
  }, [count]);

  // 使用 useCallback 缓存函数
  const handleClick = useCallback(() => {
    console.log('按钮被点击，count:', count);
  }, [count]);

  return (
    <div style={{ padding: '20px', border: '1px solid #ccc', margin: '10px' }}>
      <h3>useMemo 和 useCallback 示例</h3>
      <p>计数: {count}</p>
      <p>计算值: {expensiveValue}</p>
      <button onClick={() => setCount(count + 1)}>增加计数</button>

      <div style={{ marginTop: '10px' }}>
        <input
          type="text"
          value={text}
          onChange={e => setText(e.target.value)}
          placeholder="输入文本（不会触发重新计算）"
        />
      </div>

      <button onClick={handleClick} style={{ marginTop: '10px' }}>
        测试 useCallback
      </button>
    </div>
  );
};

// ==================== useRef 示例 ====================

/**
 * useRef - DOM 引用和可变值
 * 类似于 Vue 3 的 ref(null)
 */
const UseRefExample: React.FC = () => {
  const inputRef = useRef<HTMLInputElement>(null);
  const renderCount = useRef(0);

  renderCount.current += 1;

  const focusInput = () => {
    inputRef.current?.focus();
  };

  const getInputValue = () => {
    alert(`输入框的值: ${inputRef.current?.value}`);
  };

  return (
    <div style={{ padding: '20px', border: '1px solid #ccc', margin: '10px' }}>
      <h3>useRef 示例</h3>
      <p>组件渲染次数: {renderCount.current}</p>
      <input ref={inputRef} type="text" placeholder="点击按钮聚焦" />
      <div style={{ marginTop: '10px' }}>
        <button onClick={focusInput}>聚焦输入框</button>
        <button onClick={getInputValue}>获取输入值</button>
      </div>
    </div>
  );
};

// ==================== useImperativeHandle 和 forwardRef 示例 ====================

/**
 * useImperativeHandle - 暴露组件方法
 * forwardRef - 转发 ref
 * 类似于 Vue 3 的 expose()
 */
interface CustomInputHandle {
  focus: () => void;
  clear: () => void;
  getValue: () => string;
}

const CustomInput = forwardRef<CustomInputHandle, object>((props, ref) => {
  const inputRef = useRef<HTMLInputElement>(null);

  useImperativeHandle(ref, () => ({
    focus: () => {
      inputRef.current?.focus();
    },
    clear: () => {
      if (inputRef.current) {
        inputRef.current.value = '';
      }
    },
    getValue: () => {
      return inputRef.current?.value || '';
    },
  }));

  return <input ref={inputRef} type="text" placeholder="自定义输入框" />;
});

const UseImperativeHandleExample: React.FC = () => {
  const customInputRef = useRef<CustomInputHandle>(null);

  return (
    <div style={{ padding: '20px', border: '1px solid #ccc', margin: '10px' }}>
      <h3>useImperativeHandle 和 forwardRef 示例</h3>
      <CustomInput ref={customInputRef} />
      <div style={{ marginTop: '10px' }}>
        <button onClick={() => customInputRef.current?.focus()}>聚焦</button>
        <button onClick={() => customInputRef.current?.clear()}>清空</button>
        <button
          onClick={() => alert(`值: ${customInputRef.current?.getValue()}`)}
        >
          获取值
        </button>
      </div>
    </div>
  );
};

// ==================== useLayoutEffect 示例 ====================

/**
 * useLayoutEffect - DOM 更新后同步操作
 * 类似于 Vue 3 的 nextTick()
 */
const UseLayoutEffectExample: React.FC = () => {
  const [width, setWidth] = useState(0);
  const divRef = useRef<HTMLDivElement>(null);

  useLayoutEffect(() => {
    if (divRef.current) {
      const newWidth = divRef.current.getBoundingClientRect().width;
      setWidth(newWidth);
      console.log('useLayoutEffect - DOM 更新后立即执行');
    }
  }, []);

  return (
    <div style={{ padding: '20px', border: '1px solid #ccc', margin: '10px' }}>
      <h3>useLayoutEffect 示例</h3>
      <div
        ref={divRef}
        style={{
          width: '200px',
          height: '100px',
          backgroundColor: '#f0f0f0',
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
        }}
      >
        这个 div 的宽度是: {width}px
      </div>
    </div>
  );
};

// ==================== 自定义 Hook 示例 ====================

/**
 * 自定义 Hook - 逻辑复用
 * 类似于 Vue 3 的组合式函数
 */
function useLocalStorage<T>(key: string, initialValue: T) {
  const [storedValue, setStoredValue] = useState<T>(() => {
    try {
      const item = window.localStorage.getItem(key);
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      console.error(`读取 localStorage 键 "${key}" 时出错:`, error);
      return initialValue;
    }
  });

  const setValue = (value: T | ((val: T) => T)) => {
    try {
      const valueToStore =
        value instanceof Function ? value(storedValue) : value;
      setStoredValue(valueToStore);
      window.localStorage.setItem(key, JSON.stringify(valueToStore));
    } catch (error) {
      console.error(`设置 localStorage 键 "${key}" 时出错:`, error);
    }
  };

  useDebugValue(storedValue, value => `useLocalStorage: ${value}`);

  return [storedValue, setValue] as const;
}

const CustomHookExample: React.FC = () => {
  const [name, setName] = useLocalStorage('user-name', '');
  const [theme, setTheme] = useLocalStorage('app-theme', 'light');

  return (
    <div style={{ padding: '20px', border: '1px solid #ccc', margin: '10px' }}>
      <h3>自定义 Hook 示例 - useLocalStorage</h3>
      <div>
        <input
          type="text"
          value={name}
          onChange={e => setName(e.target.value)}
          placeholder="输入姓名（会保存到 localStorage）"
        />
        <p>保存的姓名: {name}</p>
      </div>
      <div style={{ marginTop: '10px' }}>
        <select value={theme} onChange={e => setTheme(e.target.value)}>
          <option value="light">浅色主题</option>
          <option value="dark">深色主题</option>
        </select>
        <p>当前主题: {theme}</p>
      </div>
    </div>
  );
};

// ==================== 主组件 ====================

/**
 * Hooks 演示主组件
 */
const HooksDemo: React.FC = () => {
  return (
    <div style={{ padding: '20px', fontFamily: 'Arial, sans-serif' }}>
      <h1>React Hooks 完整演示</h1>
      <p>
        这个示例展示了 React Hooks 的各种用法和与 Vue 3 Composition API 的对比
      </p>

      <UseStateExample />
      <UseEffectExample />
      <UseContextExample />
      <UseReducerExample />
      <UseMemoCallbackExample />
      <UseRefExample />
      <UseImperativeHandleExample />
      <UseLayoutEffectExample />
      <CustomHookExample />
    </div>
  );
};

export default HooksDemo;
export {
  UseStateExample,
  UseEffectExample,
  UseContextExample,
  UseReducerExample,
  UseMemoCallbackExample,
  UseRefExample,
  UseImperativeHandleExample,
  UseLayoutEffectExample,
  CustomHookExample,
};
